2018_reich_piano_phase.py

#

SPDX-FileCopyrightText: 2018 Charles Mestdagh & Michael Hoebeke SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be

SPDX-License-Identifier: GPL-3.0-or-later

#

STEVE REICH - PIANO PHASE Interprétation formelle par modèle procédural par Michael Hoebeke et Charles Mestdagh AIM JURY Janvier 2019

#

# # IMPORT BLENDER MODULES # # #

import bpy
from bpy import context as C
from bpy import data as D
from bpy import ops as O

import math
from math import radians
from math import cos
from math import sin

import random
#

NETTOYAGE PRELIMINAIRE

O.object.select_all(action="SELECT")
O.object.delete()
#

FONCTIONS

#

Definition de la fonction de création de camera en projection parallele if canon == ‘trimetrie’: #OK

def axoCam(projection, canon):
    bpy.ops.object.camera_add()
    maScene = bpy.context.scene.render
    monAxoCam = bpy.context.object
    monAxoCam.data.type = "ORTHO"
    monAxoCam.data.ortho_scale = 30
    if projection == "axonometrique":
        if canon == "isometrie":  # OK
            monAxoCam.name = "axoIsometrie"
            monAxoCam.rotation_euler = (radians(54.74), 0.0, radians(45))
            monAxoCam.location = (10.0, -10.0, 10.0)
            maScene.pixel_aspect_x = 1
        if canon == "dimetrie":  # OK
            monAxoCam.name = "axoDimetrie"
            monAxoCam.rotation_euler = (radians(60), 0.0, radians(23))
            monAxoCam.location = (5.53, -13.04, 8.18)
            maScene.pixel_aspect_x = 1
#
monAxoCam.name = 'axoTrimetrie'
monAxoCam.rotation_euler = (radians(67), 0.0, radians(34))   
monAxoCam.location = (8.59, -12.734, 6.52)
            maScene.pixel_aspect_x = 1"""
        if canon == "trimetrie":
            monAxoCam.name = "axoTrimetrie"
            monAxoCam.rotation_euler = (radians(67), 0.0, radians(34))
            monAxoCam.location = (17, -20, 5)
            maScene.pixel_aspect_x = 1
#DIVIDER

#DIVIDER
def make_cube(coord=(0, 0, 0), size=(1, 1, 1), name="Cube"):
    """Makes a capsule in coord(x,y,z)
    of size(x,y,z)
    and name'name'"""
    add_cube(coord)
    scale_cube(size)
    rename_cube(name)
    return None
#DIVIDER
def add_cube(coord):
    """adds a cube
    default position (0,0,0) tuple
    default radius 0.5 int"""
    O.mesh.primitive_cube_add(radius=0.5, location=coord)
    return None
#DIVIDER
def scale_cube(size):
    """scales a cube
    arg tuple
    cube selected!"""
    O.transform.resize(value=size)
    return None
#DIVIDER
def rename_cube(name):
    """new name for selected cube
    object and mesh affected"""
    D.objects["Cube"].name = name
    C.object.data.name = name  # no other way?
    return None
#DIVIDER
def get_objects_with_name(name):
    """returns a list of objects
    containing <name> in D.object.name"""
    objects_list = []  # c.f. next fuction for shorter method
    for item in D.objects:
        if name in item.name:
            objects_list.append(item)
    return objects_list
#DIVIDER
def get_highest(name):
    """returns a list containing
    the objects with max z value"""
    objects_list = get_objects_with_name(name)
#DIVIDER
    max_z = max([object.location.z for object in objects_list])
#DIVIDER
    return [item for item in objects_list if item.location.z == max_z]
#DIVIDER

#DIVIDER

#DIVIDER
"""Introduire ici la partition du morceau désiré, chaque note correspondant à une hauteur"""
#DIVIDER
partition = [1, 2, 5, 6, 7, 2, 1, 6, 5, 2, 7, 6]
nompartition = "Piano Phase Partie 1"
modificateur = 1.5
#DIVIDER

print(
    "\n \n \n STEVE REICH - PIANO PHASE \n interpretation formelle par modele procedural \n Partition de base:",
    nompartition,
    "-",
    partition,
    "- modificateur axe z:",
    modificateur,
)
#DIVIDER


x = int(len(partition))
pianiste1 = []

for i in range(0, x + 1):
    pianiste1.append(partition)
#DIVIDER

pianiste2 = []
copiepartition = partition[:]

for i in range(0, x + 1):
    note1 = copiepartition[:i]
    nbrdenotesajout = len(note1)
    ajout = partition + note1
    del ajout[:i]
    pianiste2.append(ajout)
#DIVIDER

ecarts = []

for i in range(0, x + 1):  # nbr de temps
    for j in range(0, x):  # nbr de notes dans la partition
        p1 = pianiste1[i]
        notep1 = p1[j]
        p2 = pianiste2[i]
        notep2 = p2[j]
        if notep1 >= notep2:
            ecart = (notep1 - notep2) * modificateur
        else:
            ecart = (notep2 - notep1) * modificateur
        ecarts.append(ecart)
#DIVIDER

minmax = []

for i in range(0, x + 1):  # nbr de temps
    for j in range(0, x):  # nbr de notes dans la partition
        p1 = pianiste1[i]
        notep1 = p1[j]
        p2 = pianiste2[i]
        notep2 = p2[j]
        minmax.append([notep1, notep2])
#DIVIDER

notemax = max(partition)
notemin = min(partition)
valeurecartneutre = notemax + notemin

positionecarts = []

for i in range(0, x + 1):  # nbr de temps
    for j in range(0, x):  # nbr de notes dans la partition
        p1 = pianiste1[i]
        notep1 = p1[j]
        p2 = pianiste2[i]
        notep2 = p2[j]
        if notep1 == notep2:
            valeurecart = 0
            diffvaleurneutre = 0
        else:
            valeurecart = notep1 + notep2
            diffvaleurneutre = valeurecart - valeurecartneutre
        positionecarts.append(diffvaleurneutre)
#DIVIDER

numdecolonneslist = range(1, (len(minmax) + 1))
numdecolonnes = set(numdecolonneslist)

infos = list(zip(numdecolonnes, minmax))
print(
    "\n Informations principales (Numero de la case/colonne sur la grille, [Note 1e pianiste, Note 2 pianiste])]: \n",
    infos,
)

print("\n Note la plus basse de la partition:", notemin)
print("Note la plus haute de la partition:", notemax)
print("Valeur de l'ecart neutre:", valeurecartneutre)
print("Hauteur des ecarts par rapport a la valeur neutre:", positionecarts)
#DIVIDER

len_ecarts = len(ecarts)

largeury = (1 / x) * 10  # largeur équivaut au nombre de notes, ramené sur 10
longueurx = (1 / (x + 1)) * 10  # longueur équivaut au nombre de temps, ramené sur 10

ecarts_copie1 = ecarts[:]
positionecarts_copie1 = positionecarts[:]
#DIVIDER
for i in range(0, x + 1):  # nbr de temps, en x
    for j in range(0, x):  # nbr de notes dans la partition, en y
        make_cube(
            (i / (x + 1) * 10, j / x * 10, 0), (longueurx, largeury, 1), "Pianiste1"
        )  # coord, size, name


pianiste1_liste = get_highest("Pianiste1")
#DIVIDER
for k in range(0, len_ecarts):
    for pianiste1 in pianiste1_liste:
        if len(ecarts_copie1) > 0:  # tant que ecarts_copie contient des elements
            z_scale = ecarts_copie1.pop(k) - positionecarts_copie1.pop(
                k
            )  # la hauteur = un écart (qui est ensuite enlevé de la liste avec pop) - valeur axe z de l'écart
            pianiste1.dimensions.z *= (
                ((x / 2) - (z_scale / 2)) / x
            ) * 10  # hauteur = moitie du cube - la moitie de l'écart (note: x/2 = moitie hauteur cube pour code dynamique, 6 par défaut
            pianiste1.location.z -= (z_scale / x * 10) / 4 - (
                x / 4
            ) / x * 10  # ajuste la position z de la colonne
#DIVIDER

ecarts_copie2 = ecarts[:]
positionecarts_copie2 = positionecarts[:]
#DIVIDER
for i in range(0, x + 1):  # nbr de temps, en x
    for j in range(0, x):  # nbr de notes dans la partition, en y
        make_cube(
            (i / (x + 1) * 10, j / x * 10, 0), (longueurx, largeury, 1), "Pianiste2"
        )  # coord, size, name


pianiste2_liste = get_highest("Pianiste2")
#DIVIDER
for k in range(0, len_ecarts):
    for pianiste2 in pianiste2_liste:
        if len(ecarts_copie2) > 0:  # tant que ecarts_copie contient des elements
            z_scale = ecarts_copie2.pop(k) + positionecarts_copie2.pop(
                k
            )  # la hauteur = un écart (qui est ensuite enlevé de la liste avec pop) + valeur axe z de l'écart
            pianiste2.dimensions.z *= (
                ((x / 2) - z_scale / 2) / x
            ) * 10  # hauteur = moitie du cube - la moitie de l'écart
            pianiste2.location.z += (z_scale / x * 10) / 4 + (
                x / 4
            ) * 3 / x * 10  # ajuste la position z de la colonne
#DIVIDER

#DIVIDER

#DIVIDER
axoCam("axonometrique", "trimetrie")
#DIVIDER

#

Fonctions pour cube

#
#

Operations on cube

#
#
#
#
#

list with all objects with ‘name’ given as function parameter

#

makes a list of the value of the z coordinate of all the objects in objects_list and returns the maximum value of that list with the operation max()

#

iterates trough the objects_list and if the objects location in z esuals max_z

#

PROGRAMME

#

PARTITION DE BASE

#

partition = [1, 2, 5, 6, 7, 2, 1, 6, 5, 2, 7, 6, 1, 2, 5, 6, 7, 2, 5, 6, 3, 4, 6, 7] nompartition = ‘Partition complète de Piano Phase’ modificateur = 2

#

partition = [1, 2, 5, 6, 7, 2, 5, 6] nompartition = ‘Piano Phase Partie 2’ modificateur = 1

partition = [3, 4, 6, 7] nompartition = ‘Piano Phase Partie 3’ modificateur = .5

partition = [9, 8, 9, 8, 7, 8, 7, 6, 6, 7, 6, 9, 6, 5, 6, 5, 4, 5, 4, 3, 13, 14, 14, 13, 12, 13, 12, 11, 12, 11] nompartition = ‘Debussy - Clair de lune’ modificateur = 3

partition = [2, 1, 3, 9, 6] nompartition = ‘Rencontre du 3e type’ modificateur = .5

#

GENERER A PARTIR DE LA PARTITION DE BASE LE MORCEAU JOUE PAR LE PREMIER PIANISTE

#

GENERER LE MORCEAU JOUE PAR LE DEUXIEME PIANISTE

#

LISTE DE TOUS LES ECARTS DE NOTES AUX MEMES MOMENTS

#

GENERER LISTE AVEC POUR CHAQUE MOMENT LES DEUX NOTES JOUEES PAR LES DEUX PIANISTES

#

CONNAITRE L’ECART MAXIMUM POSSIBLE ET MODIFIER LA POSITION DE L’ECART EN FONCTION DE SA VALEUR

#

infos console

#

GENERER PREMIER PIANISTE, STALAGMITES Hauteur des colonnes = moitié du cube - ecart/2 crée un réseau de base de (nbr de notes)x(nbr de temps) avec des cubes de 1x1x1

#

modifie la hauteur de ce réseau de base

#
#

GENERER DEUXIEME PIANISTE, STALACTITES crée un réseau de base de 12x13 avec des cubes de 1x1x1

#

modifie la hauteur de ce réseau de base

#
#

Fin du programme

#

Bonus GENERER LE NEGATIF (LE CREUX) EN POSITIF

ecarts_copie3 = ecarts[:]

crée un réseau de base de 12x13 avec des cubes de 1x1x1

for i in range(0,x+1): #nbr de temps, en x for j in range(0, x): #nbr de notes dans la partition, en y make_cube((i+20,j,(x/2)),(1,1,1),’Negatif’) #coord, size, name

negatif_liste = get_highest(‘Negatif’)

modifie la hauteur du réseau de base

for k in range(0,len_ecarts): for negatif in negatif_liste: if len(ecarts_copie3) > 0: # tant que ecarts_copie contient des elements z_scale = ecarts_copie3.pop(k) # la hauteur = un écart (qui est ensuite enlevé de la liste avec pop) negatif.dimensions.z *= z_scale # hauteur = ecart

#

PROJECTION AXONOMETRIQUE#

axoCam (‘axonometrique’,’isometrie’) axoCam (‘axonometrique’,’dimetrie’)

#

FIN DU SCRIPT